using NL;
using Sirenix.Utilities;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Security;
using UnityEngine;

namespace SinceTimes.NetWork
{
    public interface IPeerMessage
    {
        public uint Length { get;  }
        public uint Serial { get;}
        public ushort MessageType { get;  }

        public int MessageIndex { get; }


        public bool Empty { get; }

        /// <summary>
        /// 获取包的字节流
        /// </summary>
        /// <returns> </returns>
        byte[] Encode();  
        
        /// <summary>
        /// 根据字节流生成 结构.
        /// </summary>
        /// <param name="_bytes"></param>
        /// <param name="_size"></param>
        void Decode(byte[] _bytes, uint _offset, uint _size =0);
        /// <summary>
        /// 消息序列号..客户端生成.次序递增+4. 用于 1.消息返回关联,2.安全校验
        /// </summary>


        public T DataAs<T>();


    }
    public interface IPeer
    {
        GameObject gameObject { get; }

        string name { get; }
        public string Url { get; set; }
        public ushort Port { get; set; }
        public string PortList { get; set; }

        public string Error { get; }

        PeerState State { get; }
        bool Connected { get; }

        void Set(string url, ushort port, string portlist);
        string ToRuntimString();

        int Send(IPeerMessage _msg);

        IPeer WaitConnected(Action<IPeer> on);
        IPeer WaitClosed(Action<IPeer> on);

        IPeer WaitUserAuth(StringAction<IPeer , IPeerMessage> on);
    }

    public interface INetMessageGentator
    {
        float BeatHeartDuration { get; }
        byte[] Request_Message_Auth();
        byte[] Request_Message_HeartBeat();
    }

    public enum PeerState
    {
        None=0,
        Connecting=1,
        Opening=2,
        Closed=11,
    }
    public partial class Peer<M> : MonoBehaviour,IPeer  where M : IPeerMessage
    {
        PeerState IPeer.State => State;
        IPeer IPeer.WaitConnected(Action<IPeer> on)=>WaitConnected(on);

        IPeer IPeer.WaitClosed(Action<IPeer> on) => WaitCloseed(on);
        IPeer IPeer.WaitUserAuth(StringAction<IPeer, IPeerMessage> on) => WaitUserAuth(on);
        string IPeer.Url { get => URL; set => URL=value; }
        ushort IPeer.Port { get => Port; set => Port=value; }
        string IPeer.PortList { get => PortList; set => PortList = value; }
        string IPeer.Error => Error;

        [Header("服务器 地址, 端口列表(;分割)")]
        public string URL = "127.0.0.1";
        public ushort Port = 7676;
        public string PortList = "420;421";
        public void Set(string url, ushort port, string portlist)
        {
            URL = url;
            Port = port;
            PortList = portlist;
        }

        [Header("使用那种Socket通讯. 心跳")]
        public ConnectionModel Model = ConnectionModel.TCP;

        public float BeatHeartDuration = 5;


        [Header("发送帧速率.")]
        public float LockSendRate = 20;
        float _SendingDuration => LockSendRate <= 0 ? 0 : 1 / LockSendRate;


        [Header("RUNTIMES-----")]
        public Connection NowConnection;
        public string Error;

        public PeerState State = PeerState.None;
        public bool Connected=> NowConnection != null&& NowConnection.Connected;



        [SerializeField]
        public ConnectionRuntime ConnectionState;







    
        Net _PeerOwner;


        INetMessageGentator _MessageGen;
        protected virtual   void Start()
        {
            name += gameObject.GetHashCode();

            _MessageGen = GetComponentInParent<INetMessageGentator>();

            if (_MessageGen != null)
                BeatHeartDuration = _MessageGen.BeatHeartDuration;


            _PeerOwner = GetComponentInParent<Net>();
            Connect();
        }

        public Peer<M> Connect()
        {
            StopAllCoroutines();
            StartCoroutine(_ConnectRuner());
            return this;
        }
        [Header("身份验证包二次确认")]
        public bool UserAuthCheckable=true;
        //IEnumerator _ConnectRuner()
        //{
        //    yield return 0;
        //    _DoConnect();
        //}



        // 使用端口列表依次尝试..
        IEnumerator _ConnectRuner()
        {
            yield return 0;

            if (NowConnection != null && NowConnection.Connected)
            {
                NowConnection.Close();
            }

            List<ushort> all=new List<ushort>();

            // 优先按照 端口列表依次尝试..
            if(!string.IsNullOrEmpty(PortList))
            {
                all.AddRange(PortList.Split(';').Convert<ushort>(w =>
                {
                    ushort num = 0;
                    ushort.TryParse(w.ToString(), out num);
                    return num;
                }));
                Port = 0;
            }
            else
            {
                all.Add(Port);
            }


            var enumerator = all.GetEnumerator();
            while (enumerator.MoveNext()) 
            {
                // 循环尝试链接,使用端口列表..
                Port = enumerator.Current;
                if (Port > 0)
                {
                    LOG.Add($"[Peer._ConnectRuner]:_DoConnect({URL},{Port})............", 1);

                    NowConnection = _DoConnect(URL, Port);

                    if (NowConnection != null)
                    {
                        yield return NowConnection.UntilConnectOver();

                        //如果成功建立链接...就退出 循环尝试.
                        if (NowConnection.Connected)
                        {
                            LOG.Add($"[Peer._ConnectRuner]:_DoConnect({URL},{Port})=Success", 1);

                            yield break;
                        }
                    }
                }

                LOG.Add($"[Peer._ConnectRuner]:_DoConnect({URL},{Port})=Error",1);

            } 
        }

























        float _TimeOnConnecting;
        float TimePassedSinceConnecting => Time.realtimeSinceStartup - _TimeOnConnecting;
        protected virtual Connection _DoConnect(string url, ushort port)
        {

            Connection conn = null;

            _TimeOnConnecting = Time.realtimeSinceStartup;
            State = PeerState.Connecting;
            switch (Model)
            {
                case ConnectionModel.TCP:
                    conn = new ConnectionSocket(this)
                    {
                        Url = url,
                        Port = port,
                        OnConnectedCallBack = OnPeerConnect,
                        OnClosedCallBack = _DoClose,
                        OnReceivedCallBack = OnPeerReceive,
                        UserAuthCheckable = UserAuthCheckable,
                    };
                    break;
                case ConnectionModel.WebSocket:
                    conn = new ConnectionWebSocket(this)
                    {
                        Url = url,
                        Port = port,
                        OnConnectedCallBack = OnPeerConnect,
                        OnUserAuth = OnUserAuth,
                        OnClosedCallBack = _DoClose,
                        OnReceivedCallBack = OnPeerReceive,
                        UserAuthCheckable = UserAuthCheckable,
                    };
                    break;
                case ConnectionModel.HTTPWebSocket:
                    conn = new ConnectionHttpWebSocket(this)
                    {
                        Url = url,
                        Port = port,
                        OnConnectedCallBack = OnPeerConnect,
                        OnClosedCallBack = _DoClose,
                        OnReceivedCallBack = OnPeerReceive,
                        UserAuthCheckable = UserAuthCheckable,
                    };
                    break;
                case ConnectionModel.NativeWebSocket:
                    conn = new ConnectionNativeWebSocket(this)
                    {
                        Url = url,
                        Port = port,
                        OnConnectedCallBack = OnPeerConnect,
                        OnClosedCallBack = _DoClose,
                        OnReceivedCallBack = OnPeerReceive,
                        UserAuthCheckable = UserAuthCheckable,
                    };
                    break;


            }

            if (conn != null)
            {
                //是否启用 身份验证..
                if (_MessageGen != null)
                    conn.UseAuthenticate(_MessageGen.Request_Message_Auth());

                conn.Connect();

                Invoke("_TimeOut", ConnectTimeOut);
                ConnectionState = NowConnection.RuntimeState;
            }


            return conn;
        }
        public float ConnectTimeOut = 10;
        void _TimeOut()
        {
            if (State != PeerState.Opening)
                Destroy(gameObject);
        }


        public Peer<M> Close()
        {
            _DoClose(null);
            return this;
        }
        protected void _DoClose(Connection conn)
        {
            try
            {
                State = PeerState.Closed;
                if (conn != null) 
                    Error = conn.Error;

                if (NowConnection != null && NowConnection.Connected)
                {
                    NowConnection.Close(false);
                }
                else
                {
                    OnPeerClose(conn);
                }
            }
            catch
            {

            }
         
            try
            {
                _ONClosed?.Invoke(this);
            }catch
            {

            }
            try
            {
                  Destroy(gameObject);
            }catch
            {

            }


        }


        protected virtual void OnPeerConnect(Connection conn)
        {
            _LastHeartBeat = Time.realtimeSinceStartup+5;
            State = PeerState.Opening;
            _ONConnected?.Invoke(this);
            if (Net.SHOWLOG)
                Debug.Log($"[Net.Peer.OnPeerConnect] ...........");


        }
        
        protected virtual string OnUserAuth(Connection who, byte[] buff, uint offset, uint len)
        {
            //if(_ONUserAuth!=null) 
            //    return _ONUserAuth.Invoke(who, buff, offset, len);
            //else
                return "";
        }
        protected virtual void OnPeerClose(Connection conn)
        {

            if (Net.SHOWLOG)
                Debug.Log($"[Net.Peer.OnPeerClose] ...........");

        }

        byte[] _LastRemain;
        protected virtual void OnPeerReceive(byte[] buff, uint _offset, uint _size)
        {

            try
            {
                M msg;
                // 处理 粘包....
                do
                {

                    msg = _DoDecode(buff, _offset, _size);

                    

                    if(Net.SHOWLOG)
                        Debug.Log($"[Net.Peer.OnPeerReceive]:{msg} ...........");

                    _offset += msg.Length + 2;


                    _PeerOwner?.AddRecive(msg);

                    //添加 统计报告
                    _PeerOwner?.ReportReceive(msg);

                } while (msg != null && _offset < _size);


            }
            catch (Exception e)
            {
                Error = e.Message;
                if (Net.SHOWERROR)
                    Debug.LogError($"[Net.Peer.OnPeerReceive]:Error:{Error} ...........");

         
            }


        }
       
        private void OnDestroy()
        {
            //try
            //{
            //    Close();
            //}catch(Exception ex)
            //{
            //    Debug.LogError($"[Net.Peer.OnDestroy]:Error:{ex.Message} ...........");
            //}

        }




        float _LastSendClock = 0;
        float _LastHeartBeat=0;
        /// <summary>
        /// FixedUpdate 改成Update因为TimeScale=0的时候FixedUpdate不触发
        /// </summary>
        void Update()
        {
            // 获取链接状态
            if (NowConnection != null)
            {

                NowConnection.Loop();
                ConnectionState = NowConnection.RuntimeState;
            }

            //监听 链接状态
            if (!Connected)
            {
                return;
            }

            
            //心跳发送
            if (BeatHeartDuration>0 && (Time.realtimeSinceStartup - _LastHeartBeat > BeatHeartDuration) )
            {
                _LastHeartBeat = Time.realtimeSinceStartup;

                _SendHB();
              
            }

            ////处理发送...
            if (_SendingDuration > 0 && Time.realtimeSinceStartup - _LastSendClock >= _SendingDuration)
            {
                _LastSendClock = Time.realtimeSinceStartup;

                if (_PeerOwner == null) return;


                var msg = _PeerOwner.TopOneSending(0);

                if (msg != null)
                {
                    //Debug.Log($"Send msg:{msg.MessageType}");
                    Send(msg);
                }
 
            }
        }
       
        public   int Send(IPeerMessage _msg)
        {
            
            if (_msg == null) return 0;

            var buff = _msg.Encode(); ;

            int _len = NowConnection.Send(buff);


            //int _len = _SOCKETHandle.Send(buff);
            if (_len != buff.Length)
            {
                if (Net.SHOWERROR) 
                    Debug.LogError($"[Net.Peer._SOCKET.Send] Error :{_len}");
            }
            else
            {
                if (Net.SHOWLOG)
                    Debug.Log($"[Net.Peer._SOCKET.Send]OK :Len={_len} ;bytes:\n{Net.BYTES_STRING(buff)}");
            }
            //添加 统计报告
            _PeerOwner?.ReportSend(_msg);

            return _len;
            
        }

        void _SendHB()
        {
            if (_MessageGen == null || NowConnection == null)
                return;

            var data= _MessageGen.Request_Message_HeartBeat();

            if(data==null) return;

            var len= NowConnection.Send(data);


            if(Net.SHOWLOG)
                Debug.Log($"[Net.Peer._SendHB]OK :Len={len}...{Time.time}");

        }


        Action<Peer<M>> _ONConnected;
        public Peer<M> WaitConnected(Action<Peer<M>> _on)
        {
            _ONConnected= _on;
            return this;
        }

        protected StringAction<IPeer, IPeerMessage> _ONUserAuth;
        public Peer<M> WaitUserAuth(StringAction<IPeer, IPeerMessage> on)
        {
            _ONUserAuth = on; return this;
        }

        Action<Peer<M>> _ONClosed;
        public Peer< M> WaitCloseed(Action<Peer< M>> _on)
        {
            _ONClosed = _on;
            return this;
        }
        public Peer< M> Set(string _ip,ushort _port)
        {
            URL = _ip;Port = _port;return this;
        }

        protected virtual M _DoDecode(byte[] _buffer, uint _offset, uint _size)
        {
            return default(M);
        }


        public string ToRuntimString() => ConnectionState.ToString();

        public override string ToString()
        {
            return $"{name}:<{URL}@{Port}>  {ToRuntimString()}" ;
        }

    }
}

